#pragma once
#include "log.hpp"
#include "cond.hpp"
#include "thread.hpp"
using namespace td;
const int N = 5;
template <class T>
class Threadpool
{
private:
  Threadpool(int num = N) : _size(num),_sleepingnums(0),_isrunning(0)
  {
    for (int i = 0; i < _size; i++)
    {
      _threads.push_back(Thread([this]()
                                { this->handletask(); }));
    }
  }
  // 单例只允许实例出一个对象
  Threadpool(const Threadpool<T> &t) = delete;
  Threadpool<T> &operator=(const Threadpool<T> &t) = delete;

  void Start()
  {
    if (_isrunning)//勿忘标记位
      return;
    _isrunning = true;
    for (int i = 0; i < _size; i++)
    {
     // use_log(loglevel::DEBUG) << "成功启动一个线程";
      ;
      _threads[i].start();
    }
  }

public:
  static Threadpool<T> *getinstance()//必须采用静态(不创建对象的前提下进行获得类指针)
  {
    if (_ins == nullptr) //双重判断-->假设一个线程很快完成单例化；然后后面的一群线程正好来了；如果没有双层判断；就会阻塞一个个发现不是空返回_ins；
                         //非常慢；为了提高效率这样就不用加锁在一个个判断了还能保证线程安全。
    {
      {
        mutexguard mg(_lock);//静态锁；
        if (_ins == nullptr)
        {
          _ins = new Threadpool<T>();
          use_log(loglevel::DEBUG) << "创建一个单例";
          _ins->Start();//创建单例自启动
        }
      }
    }
    use_log(loglevel::DEBUG) << "获得之前创建的一个单例";
    return _ins;
  }

  void stop()//不能立刻停止如果队列有任务还需要线程完成完然后从handl函数退出即可
  {
    mutexguard mg(_Mutex);//这里为了防止多线程调用线程池但是单例化杜绝了这点
    if (_isrunning)
    {
      _isrunning = 0;//因此只搞个标记
      use_log(loglevel::DEBUG) << "唤醒所有线程";
    //被唤醒后没有抢到锁的线程虽然休眠但是不用再次唤醒了；os内设它就会让它所只要出现就去竞争
      _Cond.allnotify();//万一还有其他线程还在休眠就需要都唤醒-->全部子线程都要退出
    }

    return;
  }

  void join()

  {
    // mutexguard mg(_Mutex);这里不能加锁；如果join的主线程快的话；直接就拿到锁了
    // 即使唤醒子线程；他们都拿不到锁故继续休眠等待锁；而主线程join这一直拿着 锁等子线程
    // 故造成了---->死锁问题
    // 但是可能出现多线程同时访问；后面把它设置单单例模式就好了
    use_log(loglevel::DEBUG) << "回收线程";
    for (int i = 0; i < _size; i++)
      _threads[i].join();
  }
  bool equeue(const T &tk)
  {
    mutexguard mg(_Mutex);
    if (_isrunning)
    {
      _task.push(tk);
      if (_sleepingnums == _size)
        _Cond.notify(); // 全休眠必须唤醒一个执行
      //use_log(loglevel::DEBUG) << "成功插入一个任务并唤醒一个线程";
      return true;
    }
    return false;
  }
  void handletask()
  { // 类似popqueue
    char name[128];//在线程局部存储开；不用加锁非全局就行
    pthread_getname_np(pthread_self(), name, sizeof(name));
    while (1)
    {
      T t;
      {
        mutexguard gd(_Mutex);

        while (_task.empty() && _isrunning)//休眠条件
        {
          _sleepingnums++;
          _Cond.Wait(_Mutex);
          _sleepingnums--;
          // cout<<1<<endl;
        }
        if (_task.empty() && !_isrunning)//醒来后发现符合退出条件就退出
        {
          use_log(loglevel::DEBUG) << name << "退出";
          break; // 代码块执行完了；锁自动释放
        }
        t = _task.front();
        _task.pop();
      }
     t();
   

    }
  }

  ~Threadpool() {}

private:
  vector<Thread> _threads;
  int _size;
  mutex _Mutex;
  cond _Cond;
  queue<T> _task;
  bool _isrunning;
  int _sleepingnums;
  //仅仅只是声明
  static Threadpool<T> *_ins;
  static mutex _lock;
};
//类内声明内外定义初始化
template<class T>
Threadpool<T>*Threadpool<T> ::_ins=nullptr;
template<class T>
mutex Threadpool<T> ::_lock;

